package com.taichuan.selfcheck.service;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
import androidx.annotation.Nullable;
import com.a64.a64board.TcA64GpioActionListener;
import com.a64.a64board.TcA64GpioClient;
import com.g3288.g3288board.Rk3399GpioActionDefine;
import com.g3288.g3288board.TcRk3399GpioClient;
import com.orhanobut.logger.Logger;
import com.taichuan.selfcheck.eventbus.AlarmInputEvent;
import com.taichuan.selfcheck.eventbus.DoorCheckEvent;
import com.taichuan.selfcheck.eventbus.DoorOpenStateEvent;
import com.taichuan.selfcheck.eventbus.FillLightPwmEvent;
import com.taichuan.selfcheck.eventbus.LeftCaseFanStateEvent;
import com.taichuan.selfcheck.eventbus.LightPowerEvent;
import com.taichuan.selfcheck.eventbus.McuSendUpdatePackageResultEvent;
import com.taichuan.selfcheck.eventbus.McuUpdateCheckResultEvent;
import com.taichuan.selfcheck.eventbus.McuVersionEvent;
import com.taichuan.selfcheck.eventbus.MicrowaveEvent;
import com.taichuan.selfcheck.eventbus.OutUnlockEvent;
import com.taichuan.selfcheck.eventbus.QrcodeEvent;
import com.taichuan.selfcheck.eventbus.ReadSenseTemperatureValueEvent;
import com.taichuan.selfcheck.eventbus.ReservedIoEvent;
import com.taichuan.selfcheck.eventbus.RightCaseFanStateEvent;
import com.taichuan.selfcheck.eventbus.Serial485DataEvent;
import com.taichuan.selfcheck.eventbus.SwipeCardEvent;
import com.taichuan.selfcheck.eventbus.TamperStateEvent;
import com.taichuan.selfcheck.eventbus.TempEvent;
import com.taichuan.selfcheck.eventbus.TempFragmentOpenEvent;
import com.taichuan.selfcheck.hardware.finger.FingerControlClient;
import com.taichuan.selfcheck.ui.activity.MainActivity;
import com.taichuan.serialcommunication.ISerialPort485DataListener;
import com.taichuan.serialcommunication.ISerialPortActionListener;
import com.taichuan.serialcommunication.ISerialPortMcuUpdateListener;
import com.taichuan.serialcommunication.ISerialPortQrcodeListener;
import com.taichuan.serialcommunication.SDKInitListener;
import com.taichuan.serialcommunication.SPIUtils;
import com.taichuan.serialcommunication.SerialPortPublic;
import com.taichuan.serialcommunication.readsenseTemp.ReadSenseTemperatureHelper;
import com.taichuan.serialcommunication.readsenseTemp.ReadSenseTemperaturePacket;
import com.taichuan.tcutils.HexUtils;
import com.taichuan.tcutils.taichuan.SystemUtils;
import com.taichuan.tcutils.taichuan.TcDeviceType;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;

/**
 * 该类主要用于
 *
 * @author CamelLuo
 * @version 2019/12/5
 */
public class SelfcheckSerialPortService extends Service {
    private static final String TAG = SelfcheckSerialPortService.class.getSimpleName();
    /**
     * 定义一个变量用于表示 SelfcheckSerialPortService 是否初始化过串口库
     */
    private boolean isStartSerialPort = false;
    /**
     * 定义一个变量用于控制程序是否启用单片机看门狗功能
     * 开启后如果程序遭遇异常崩溃或系统卡死，硬件异常等导致 喂狗线程无法运行的现象
     * 单片机在30秒后将自动复位设备，防止设备一直异常
     * true 为进入调试模式，关闭看门狗
     * false 为进入正式模式，开启看门狗
     */
    private boolean isCloseFeedDog = true;

    /**
     * 定义一个变量用于表示本次Service启动是否经历了 onCreate() 生命周期
     */
    private boolean isOnCreate = false;

    /**
     * 定义一个变量用于表示测试自检程序是否开启了温度测试界面
     */
    private boolean isOpenTempFragment = false;

    @Override
    public void onCreate() {
        super.onCreate();
        Log.i(TAG, "onCreate: 太川功能测试自检程序SerialPortService 正在执行 onCreate() 方法");
        //Service服务执行过onCreate() 生命周期
        isOnCreate = true;
        //注册EventBus
        EventBus.getDefault().register(this);
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.i(TAG, "onStartCommand: 太川功能测试自检程序SerialPortService 正在执行 onStartCommand() 方法 | isOnCreate为： " + isOnCreate);
        if (isOnCreate){
            //获取传递的参数信息
            if (intent != null){
                isCloseFeedDog = intent.getBooleanExtra(MainActivity.TC_SELF_CHECK_PARAM_IS_CLOSE_FEED_DOG,true);
                Log.e(TAG, "onStartCommand: 获取到参数信息 | 是否需要 关闭看门狗： " + isCloseFeedDog);
            }
            //初始化串口库
            initSerialPort();
            //初始化gpio库
            initGpio();

            //设备支持指纹识别功能
            if (SystemUtils.isSupportZazFingerDevice()){
                //初始化指纹识别模块
                FingerControlClient.getInstance().init(this);
            }

            //Service服务执行 onStartCommand() 生命周期 完毕，将标志位重置
            isOnCreate = false;
        }else {
            Log.i(TAG, "onStartCommand: 太川功能测试自检程序SerialPortService 正在执行 onStartCommand() 方法,此时为二次启动Service");
        }
        //不允许自动重启Service
        return START_NOT_STICKY;
    }

    /**
     * 定义一个方法用于根据设备类型型号决定是否需要初始化gpio库
     */
    private void initGpio() {
        //根据设备类型型号决定是否需要初始化Gpio库
        if (SystemUtils.getTcDeviceType() == TcDeviceType.A33_VERTICAL_TOUCH) {          //A33 竖屏触摸 设备
            //A33的gpio库无需初始化，直接单例调用方法即可

        } else if (SystemUtils.getTcDeviceType() == TcDeviceType.A64_VERTICAL_TOUCH_FOR_HANVON_DEVICE) {    //A64 竖屏触摸 设备
            //初始化A64的gpio库 第一个参数为是否开启gpio读取线程，第二个参数为是否开启debug模式
            int result = TcA64GpioClient.getInstance().initGpio(true, false);
            //注册事件监听
            TcA64GpioClient.getInstance().addFaceInitedListener(TAG, a64GpioActionListener);
            Log.e(TAG, "initGpio: A64 竖屏触摸 设备（汉王模块方案设备） 初始化gpio库结果：  " + result);
        } else if (SystemUtils.getTcDeviceType() == TcDeviceType.A64_VERTICAL_TOUCH ||
                SystemUtils.getTcDeviceType() == TcDeviceType.A64_VERTICAL_TOUCH_HZ01 ||
                SystemUtils.getTcDeviceType() == TcDeviceType.A64_VERTICAL_KEY ||
                SystemUtils.getTcDeviceType() == TcDeviceType.L10_Pro){         //A64 使用USB摄像头方案的设备
            //初始化A64的gpio库 第一个参数为是否开启gpio读取线程，第二个参数为是否开启debug模式
            int result = TcA64GpioClient.getInstance().initGpio(false, true);
            Log.e(TAG, "initGpio: A64 竖屏触摸/按键 设备(超薄) || L10Pro设备 || TC-Y9D-HZ01设备 初始化gpio库结果：  " + result);
        }else if (SystemUtils.isRk3399()) {                                                //Rk3399 设备
            int result = TcRk3399GpioClient.getInstance().initGpio(false);
            Log.e(TAG, "initGpio: Rk3399 设备 初始化gpio库结果： " + result);
            if (SystemUtils.getTcDeviceType() == TcDeviceType.RK3399_VERTICAL_TOUCH_O8A_DOOR){
                /**
                 * TC-Y9D-O8A因485硬件电路设计特殊，无法实现485的自动收发功能
                 * 必须手动控制485的IO口来进行 接收和发送的模式切换
                 * 因目前V5暂时没有使用485发送梯控协议，因此将设备的485模式启动为 接收模式
                 */
                TcRk3399GpioClient.getInstance().controlGpio(Rk3399GpioActionDefine.CHANGE_TC_Y9D_O8A_485_RECEIVE_MODE);
            }
        }
        else {                                                                         //未知设备

        }
    }

    /**
     * A64 竖屏触摸板设备 gpio库事件监听回调
     */
    private final TcA64GpioActionListener a64GpioActionListener = new TcA64GpioActionListener() {

        @Override
        public void onMicrowaveState(boolean b) {
            if (SystemUtils.getTcDeviceType() == TcDeviceType.A64_VERTICAL_TOUCH_FOR_HANVON_DEVICE) {    //A64 竖屏触摸 设备
                //发布EventBus事件，通知外部组件微波模块状态
                EventBus.getDefault().post(new MicrowaveEvent(b));
            }
        }
    };

    @Override
    public void onDestroy() {
        super.onDestroy();
        //注销Eventbus
        EventBus.getDefault().unregister(this);

        // 移除串口通讯监听器
        SerialPortPublic.removeSerialPortActionListener(mSerialPortActionListener);
        SerialPortPublic.removeSerialPort485DataListener(mSerialPort485DataListener);
        if (SystemUtils.isSupportMcuUpdate()){
            SerialPortPublic.removeSerialPortMcuUpdateListener(mcuUpdateListener);
        }

        //注销串口库
        SerialPortPublic.uninit(this);
        //根据设备类型决定是否需要注销gpio库
        destoryGpio();
        Log.i(TAG, "onDestroy: 太川功能测试自检程序SerialPortService 正在执行 onDestroy() 方法");
    }

    /**
     * 定义一个方法用于初始化串口库
     */
    protected void initSerialPort() {
        Logger.t(TAG).i("onCreate: 太川自检程序初始化的 串口通讯SDK版本：" + SerialPortPublic.getsdkInfo() + " 是否关闭看门狗：  " + isCloseFeedDog);
        SerialPortPublic.setSdkInitListener(mSdkInitListener);
        // 添加串口通讯单片机监听器
        SerialPortPublic.addSerialPortActionListener(mSerialPortActionListener);
        // 添加串口通讯485监听器
        SerialPortPublic.addSerialPort485DataListener(mSerialPort485DataListener);
        // 添加二维码监听器
        SerialPortPublic.addSerialPortQrcodeListener(mSerialPortQrcodeListener);
        if (SystemUtils.isSupportMcuUpdate()){
            //注册单片机升级事件监听器
            SerialPortPublic.addSerialPortMcuUpdateListener(mcuUpdateListener);
        }

        //TC-Y9D-B8A(YY)(20DBoard)(Temp)-WIFI 设备,需要接入 阅面人脸 测温模块，因此波特率需要设置为115200，才能正常工作
        if (SystemUtils.isTC5000D_XL5_4G_WIFI_TempBoard()) {
            SerialPortPublic.setSp485Config(115200,50,512);
        }

        // 初始化串口通讯SDK —— 初始化单片机（包括人脸和指纹）和485 【第二个boolean参数为 是否启动看门狗】
        // （启动喂狗的话，如果系统死机或程序奔溃导致喂狗超时，单片机会断电重启设备）
        if (SystemUtils.getTcDeviceType() == TcDeviceType.RK3399_VANKE_SITE_BOX){           //万科智慧工地项目 设备 主板
            //只初始化单片机串口
            SerialPortPublic.init(this.getApplicationContext(), isCloseFeedDog,true,true);
        }else {             //其他设备
            SerialPortPublic.initWith485(this.getApplicationContext(), isCloseFeedDog,true,true);
        }
    }

    /**
     * 定义一个方法用于根据设备类型型号决定是否需要注销gpio库
     */
    private void destoryGpio() {
        //根据设备类型型号决定是否需要初始化Gpio库
        if (SystemUtils.getTcDeviceType() == TcDeviceType.A33_VERTICAL_TOUCH) {          //A33 竖屏触摸 设备
            //A33的gpio库无需注销

        } else if (SystemUtils.getTcDeviceType() == TcDeviceType.A64_VERTICAL_TOUCH_FOR_HANVON_DEVICE) {    //A64 竖屏触摸 设备
            //注销事件监听
            TcA64GpioClient.getInstance().removeFaceInitedListener(TAG);
            //注销gpio库
            int result = TcA64GpioClient.getInstance().destoryGpio();
            Log.e(TAG, "destoryGpio: 注销 A64 gpio库结果：  " + result);
        } else if (SystemUtils.isRk3399()){
            int result = TcRk3399GpioClient.getInstance().destoryGpio();
            Log.e(TAG, "destoryGpio: 注销 Rk3399 gpio库结果：  " + result);
        } else {                                                                         //未知设备

        }
    }

    /**
     * 串口通讯初始化状态监听器
     */
    SDKInitListener mSdkInitListener = new SDKInitListener() {
        @Override
        public void SDKInited() {
            Logger.t(TAG).i("SDKInited: 串口通讯SDK初始化成功");

        }

        @Override
        public void SDKLosted() {
            Logger.t(TAG).i("SDKLosted: 串口通讯SDK初始化失败");

        }
    };

    /**
     * 串口通讯单片 硬件消息事件监听器
     */
    ISerialPortActionListener mSerialPortActionListener = new ISerialPortActionListener() {
        /**
         * 门检开关状态
         * @param isOn true 门状态为开，false 门状态关
         */
        @Override
        public void onDoorSwitchStatus(boolean isOn) {
            Logger.t(TAG).i("onDoorSwitchStatus: 门检开关状态：" + (isOn ? "开" : "关"));
            //发布订阅事件通知外部组件
            EventBus.getDefault().post(new DoorCheckEvent(isOn));
        }

        @Override
        public void onDoorOpenStatus(boolean isOpenDoor) {
            Logger.t(TAG).i("onDoorOpenStatus: 门开关状态：" + (isOpenDoor ? "开" : "关"));
            //发布订阅事件通知外部组件
            EventBus.getDefault().post(new DoorOpenStateEvent(isOpenDoor));
        }

        /**
         * 防拆报警，触发后会持续报警回调
         * @param isTamper true 设备被拆除，报警
         */
        @Override
        public void onTamperAlways(boolean isTamper) {
            Logger.t(TAG).i("onTamperAlways: 防拆状态：" + isTamper);
            //发布订阅事件通知外部组件
            EventBus.getDefault().post(new TamperStateEvent(isTamper));
        }

        /**
         * 外出开关
         * @param isOut true 短路-开门
         */
        @Override
        public void onOutSwitch(boolean isOut) {
            Logger.t(TAG).i("onOutSwitch: 外出开关：" + isOut);
            EventBus.getDefault().post(new OutUnlockEvent(isOut));
        }

        @Override
        public void onPhysicsKeyDown(int i) {
            Logger.t(TAG).i("onPhysicsKeyDown: 键盘按下的键值：" + i);

            //将收到的键值以EventBus事件发送出去
            // TODO 此时因 JDK1.5 的特性 自动将 int 封包为 Integer 对象，所以注册事件时，方法的参数需要设置为Integer
            EventBus.getDefault().post(i);
        }

        /**
         *
         * @param light 光照，值越大表示越亮
         * @param power 电量
         */
        @Override
        public void onLightPowerResult(int light, int power) {
            Logger.t(TAG).i("onLightPowerResult: 光照值：" + light + "，电量值" + power);
            EventBus.getDefault().post(new LightPowerEvent(light));
        }

        @Override
        public void onWriteDeviceIdResult(boolean b) {
            Logger.t(TAG).i("onWriteDeviceIdResult: 设备号写入结果：" + b);
        }

        @Override
        public void onReadDeviceIdResult(boolean b, String s, String s1) {
            Logger.t(TAG).i("onReadDeviceIdResult: 设备号读取结果：" + b + "，设备号：" + s + "，以太网MAC：" + s1);
            if (SystemUtils.isTC5000D_XL5_4G_WIFI_TempBoard()) {
                ReadSenseTemperatureHelper.getInstance().switchMode(ReadSenseTemperaturePacket.protocol_mode2_command);
            }
        }

        @Override
        public void onCardResult(boolean b, String s) {
            Logger.t(TAG).i("onCardResult: 卡号：" + s + "，是否后置刷卡器：" + b);
            EventBus.getDefault().post(new SwipeCardEvent(s, b));
        }

        @Override
        public void onBlueToothResult(String s) {
            Logger.t(TAG).i("onBlueToothResult: 接收到蓝牙数据：" + s);
        }

        @Override
        public void onVersion(String s) {
            Logger.t(TAG).i("onVersion: 单片机版本：" + s);
            //发布订阅事件通知外部组件
            EventBus.getDefault().post(new McuVersionEvent(s));
        }

        @Override
        public void onACCheck(boolean b) {
            //该回调接口命名有误，现为微波模块状态回调
            Logger.t(TAG).i("onACCheck: 微波模块状态：" + b);
            //发布订阅事件通知外部组件
            EventBus.getDefault().post(new MicrowaveEvent(b));
        }

        @Override
        public void onLowPowerCheck(boolean b) {
            Logger.t(TAG).i("onLowPowerCheck: 低电检测状态(预留IO口)：" + b);
            //发布订阅事件通知外部组件
            EventBus.getDefault().post(new ReservedIoEvent(b));
        }

        @Override
        public void onBodyTemp(int temp, int distance) {
            if (isOpenTempFragment){
                Logger.t(TAG).i("onBodyTemp: 温度：" + temp);
                EventBus.getDefault().post(new TempEvent(temp));
            }
        }

        @Override
        public void onMicrowaveResult(boolean b) {
            Logger.t(TAG).i("onMicrowaveResult: Rk3399 微波模块状态：" + b);
            //发布订阅事件通知外部组件
            EventBus.getDefault().post(new MicrowaveEvent(b));
        }

        @Override
        public void onAlarmInput(boolean alarm) {
            Logger.t(TAG).i("onAlarmInput: Rk3399 输入报警：alarm=" + alarm);
            EventBus.getDefault().post(new AlarmInputEvent(alarm));
        }

        @Override
        public void onFillLightPwm(boolean open, int pwm) {
            Logger.t(TAG).i("onFillLightPwm: Rk3399 补光灯pwm调节：open=" + open + ", pwm=" + pwm);
            EventBus.getDefault().post(new FillLightPwmEvent(open, pwm));
        }

        /**
         * 该方法目前仅用于 万科智慧工地项目
         * 机箱 左侧风扇 当前 转动状态 的 回调结果
         * 当外部组件通过单片机SDK控制机箱风扇开始转动后，如风扇硬件与接线正常：
         * 左风扇 应该反馈为true
         * 当外部组件通过单片机SDK控制机箱风扇停止转动后，如风扇硬件与接线正常：
         * 左风扇 应该反馈为false
         * 当机箱风扇已经处于转动状态，此时人为手动停止左风扇和右风扇：
         * 左风扇 应该反馈为false
         *
         * @param isLeftFanOpen 左侧机箱风扇 是否正常转动
         *                      true为正常转动
         *                      false为停止转动
         */
        @Override
        public void onCaseLeftFanCheckResult(boolean isLeftFanOpen) {
            Log.i(TAG, "onCaseLeftFanCheckResult: 左侧机箱风扇 是否开始转动：" + isLeftFanOpen);
            EventBus.getDefault().post(new LeftCaseFanStateEvent(isLeftFanOpen));
        }

        /**
         * 该方法目前仅用于 万科智慧工地项目
         * 机箱 右侧风扇 当前 转动状态 的 回调结果
         * 当外部组件通过单片机SDK控制机箱风扇开始转动后，如风扇硬件与接线正常：
         * 右风扇 应该反馈为true
         * 当外部组件通过单片机SDK控制机箱风扇停止转动后，如风扇硬件与接线正常：
         * 右风扇 应该反馈为false
         * 当机箱风扇已经处于转动状态，此时人为手动停止左风扇和右风扇：
         * 右风扇 应该反馈为false
         *
         * @param isRightFanOpen 右侧机箱风扇 是否正常转动
         *                       true为正常转动
         *                       false为停止转动
         */
        @Override
        public void onCaseRightFanCheckResult(boolean isRightFanOpen) {
            Log.i(TAG, "onCaseLeftFanCheckResult: 右侧机箱风扇 是否开始转动：" + isRightFanOpen);
            EventBus.getDefault().post(new RightCaseFanStateEvent(isRightFanOpen));
        }
    };

    private final ISerialPortQrcodeListener mSerialPortQrcodeListener = new ISerialPortQrcodeListener() {
        @Override
        public void onPassThroughData(byte[] data) {
            EventBus.getDefault().post(new QrcodeEvent(data));
        }

        @Override
        public void onQrcodeDledStatus(int status) {

        }

        @Override
        public void onQrcodeResStatus(int status, int ms) {

        }

        @Override
        public void onQrcodeTrigStatus(int status, int ms) {

        }
    };

    @Subscribe
    public void receiveTempFragmentOpenState(TempFragmentOpenEvent tempFragmentOpenEvent){
        if (tempFragmentOpenEvent != null){
            Log.e(TAG, "receiveTempFragmentOpenState: 收到了程序温度测试页面开关状态事件，是否开启页面： " + tempFragmentOpenEvent.isOpen());
            isOpenTempFragment = tempFragmentOpenEvent.isOpen();
        }
    }

    /**
     * 单片机升级功能回调接口
     */
    private ISerialPortMcuUpdateListener mcuUpdateListener = new ISerialPortMcuUpdateListener() {
        /**
         * 单片机程序升级检测结果
         * @param mcuCheckUpdateType 1为允许升级，可以发送升级包
         *                           2为设备的单片机程序已经为最新版本
         *                           3.设备单片机程序升级失败，已切换至紧急备用程序
         *
         */
        @Override
        public void onMcuUpdateCheckResult(int mcuCheckUpdateType) {
            EventBus.getDefault().post(new McuUpdateCheckResultEvent(mcuCheckUpdateType));
        }

        /**
         * 单片机升级程序数据包发送进度回复结果
         * @param receiveResultType 单片机接收升级包数据结果类型，1：数据已成功写入单片机
         *                                                        2：数据写入单片机失败
         * @param totalPackageCount 本次单片机程序升级包所需要发送的总包数
         * @param currentPackageNum 本次发送的包序号(从1开始)
         */
        @Override
        public void onMcuSendUpdatePackageResult(int receiveResultType, int totalPackageCount, int currentPackageNum) {
            EventBus.getDefault().post(new McuSendUpdatePackageResultEvent(receiveResultType,totalPackageCount,currentPackageNum));
        }
    };

    /**
     * 串口通讯485监听器
     */
    ISerialPort485DataListener mSerialPort485DataListener = new ISerialPort485DataListener() {
        @Override
        public void receivedData(byte[] bytes) {
            if (SystemUtils.isTC5000D_XL5_4G_WIFI_TempBoard()){     //TC-Y9D-B8A(YY)(20DBoard)(Temp)-WIFI 设备
                //测温数据
                Log.e(TAG, "receivedData: 接收到测温数据: " + HexUtils.getFormatHex(bytes));

                //TODO 待实现，将上报的温度协议数据转换为温度值
                EventBus.getDefault().post(new ReadSenseTemperatureValueEvent(ReadSenseTemperatureHelper.getInstance().getDealData(bytes)));

            }else {                 //常规设备 - 默认为 485刷卡
                Logger.t(TAG).i("receivedData: 接收到485 刷卡数据：" + HexUtils.getFormatHex(bytes));
                String cardFor485 = HexUtils.getFormatHexNonSpace(bytes);
                //将卡号补全至16位
                String standardCard = SPIUtils.getStandardCard(cardFor485);
                Logger.t(TAG).i("接收到的485 刷卡标准卡号为： " + standardCard);
                EventBus.getDefault().post(new Serial485DataEvent(bytes,standardCard));
            }

        }
    };
}
